void Main()
{
var input = File.ReadAllLines(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), "..", "day20.txt")).ToList();
var tiles = ReadTiles(input.GetEnumerator()).ToArray();
var corners = tiles.Where(t => tiles.Where(o => o.Id != t.Id).Count(o => t.CanTouch(o)) == 2).ToArray();
var part1 = corners.Select(t => t.Id).Aggregate ((x, y) => x * y);
part1.Dump();
var size = (int)Math.Sqrt(tiles.Count());
var layout = new Tile[size,size];
for(int row=0; row tiles.Where(o => o.Id != c.Id).Count(o => o.PossibleEdges.Contains(c.BottomEdge)) == 1 &&
tiles.Where(o => o.Id != c.Id).Count(o => o.PossibleEdges.Contains(c.RightEdge)) == 1))
layout[row, col] = c;
}else if (row ==0) {
var existing = layout[0,col-1];
foreach( var candidate in tiles.Where(t => t.Id != existing.Id).Where(o => o.PossibleEdges.Contains(existing.RightEdge))){
if (candidate.SpinAndFlipUntil (() => existing.RightEdge == candidate.LeftEdge))
layout[row,col]=candidate;
break;
}
}else{
var existing = layout[row - 1,col];
foreach (var candidate in tiles.Where(t => t.Id != existing.Id).Where(o => o.PossibleEdges.Contains(existing.BottomEdge)))
if (candidate.SpinAndFlipUntil(() => existing.BottomEdge == candidate.TopEdge))
{
layout[row, col] = candidate;
break;
}
}
}
}
//assemble the image
var w = tiles.First().Bits.GetLength(1) - 2;
var h = tiles.First().Bits.GetLength(0)-2;
var image = new char[layout.GetLength(0)*h,layout.GetLength(1)*w ];
for(int row=0; row o.ToCharArray()).ToArray().To2DArray();
bool FindSeaMonster(int row, int col) {
if (row+seaMonster.GetLength(0) > image.GetLength(0) || col+seaMonster.GetLength(1) > image.GetLength(1))
return false;
for (int r = 0; r Enumerable.Range(0, image.GetLength(1)).Count(col => FindSeaMonster(row,col)));
var ctr = 0;
while (monsters == 0){
image = image.RotateArray();
if (++ctr == 4) image= image.FlipArray();
monsters = Enumerable.Range(0, image.GetLength(0)).Sum(row => Enumerable.Range(0, image.GetLength(1)).Count(col => FindSeaMonster(row,col)));
}
var part2 = image.ToEnumerable().Count(i => i=='#') - (monsters * seaMonster.ToEnumerable().Count(i => i=='#'));
part2.Dump();
}
IEnumerable ReadTiles(IEnumerator e)
{
while (e.MoveNext())
{
var tileid = int.Parse(((string)e.Current).Substring(5, 4));
var lines = new List();
e.MoveNext();
while (!string.IsNullOrEmpty(e.Current))
{
lines.Add(e.Current);
e.MoveNext();
}
yield return new Tile(tileid, lines.Select(l => l.ToCharArray().ToArray()).ToArray().To2DArray() );
}
}
public class Tile
{
public Tile(long id, char[,] bits)
{
Id = id;
Bits = bits;
}
public long Id { get; private set; }
public char[,] Bits { get; private set; }
private List _possibleEdges;
public List PossibleEdges
{
get
{
if (_possibleEdges == null)
{
_possibleEdges = new List { TopEdge, BottomEdge, LeftEdge, RightEdge, new string(TopEdge.Reverse().ToArray()), new string(BottomEdge.Reverse().ToArray()), new string(LeftEdge.Reverse().ToArray()), new string(RightEdge.Reverse().ToArray()) };
}
return _possibleEdges;
}
}
public void Rotate() { Bits = Bits.RotateArray(); }
public void Flip() { Bits = Bits.FlipArray() ; }
public string TopEdge => new string(Enumerable.Range(0, Bits.GetLength(1)).Select(col => Bits[0, col]).ToArray());
public string BottomEdge => new string(Enumerable.Range(0, Bits.GetLength(1)).Select(col => Bits[ Bits.GetLength(0)-1, col]).ToArray());
public string LeftEdge => new string(Enumerable.Range(0, Bits.GetLength(0)).Select(row => Bits[row, 0]).ToArray());
public string RightEdge => new string(Enumerable.Range(0, Bits.GetLength(0)).Select(row => Bits[row, Bits.GetLength(1)-1]).ToArray());
public bool CanTouch(Tile other) => PossibleEdges.Any(e => other.PossibleEdges.Contains(e));
public bool SpinAndFlipUntil(Func condition)
{
for (int opt = 0; opt < 9; opt++)
{
if (condition())
return true;
Rotate();
if (opt == 4) Flip();
}
return false;
}
}
public static class Helpers
{
public static T[,] RotateArray(this T[,] src)
{
int oRows = src.GetLength(0);
int oCols = src.GetLength(1);
int nRows = oCols;
int nCols = oRows;
T[,] ret = new T[nRows, nCols];
int oldRow;
for (int newRow = 0; newRow < nRows; newRow++)
{
oldRow = oRows -1;
for (int newCol = 0; newCol < nCols; newCol++)
ret[newRow, newCol] = src[oldRow--, newRow];
}
return ret;
}
public static T[,] FlipArray(this T[,] src)
{
int rows = src.GetLength(0);
int cols = src.GetLength(1);
T[,] ret = new T[rows, cols];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
ret[i, j] = src[i, cols - j - 1];
}
}
return ret;
}
public static T[,] To2DArray(this IList> src)
{
int max = src.Select(l => l).Max(l => l.Count());
var ret = new T[src.Count, max];
for (int i = 0; i < src.Count; i++)
{
for (int j = 0; j < src[i].Count(); j++)
{
ret[i, j] = src[i][j];
}
}
return ret;
}
public static void Copy2DArray(ref T[,] dest, int destCol, int destRow, T[,] source, int? sourceCol = null, int? sourceRow = null, int? cols = null, int? rows = null)
{
// no error checking...
var rowsToCopy = rows ?? source.GetLength(0) - sourceRow ?? source.GetLength(0);
var colsToCopy = cols ?? source.GetLength(1) - sourceCol ?? source.GetLength(1);
for (int r = 0; r < rowsToCopy; r++)
{
for (int c = 0; c < colsToCopy; c++)
{
dest[destRow + r, destCol + c] = source[sourceRow.GetValueOrDefault() + r, sourceCol.GetValueOrDefault() + c];
}
}
}
public static IEnumerable ToEnumerable(this T[,] src)
{
for (int r=0; r